package com.rain.rainspringboot3.encryption.aspect;


import com.rain.rainspringboot3.encryption.annotation.EnableEncryption;
import com.rain.rainspringboot3.encryption.enums.CRUDType;
import com.rain.rainspringboot3.encryption.service.EncryptionService;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 加密切面
 * 拦截带有@EnableEncryption注解的方法，自动处理加解密
 */
@Aspect
@Component
@AllArgsConstructor
public class EncryptionAspect {

    private final EncryptionService encryptionService;
    
    @Around("@annotation(com.rain.rainspringboot3.encryption.annotation.EnableEncryption)")
    public Object processEncryption(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法上的EnableEncryption注解
        EnableEncryption methodAnnotation = method.getAnnotation(EnableEncryption.class);

        // 获取方法参数
        Object[] args = joinPoint.getArgs();

        if (methodAnnotation != null) {
            CRUDType type = methodAnnotation.type();
            switch (type) {
                case INSERT, UPDATE -> {
                    // 处理参数加密
                    for (int i = 0; i < args.length; i++) {
                        if (args[i] != null) {
                            args[i] = encryptionService.encryptObject(args[i]);
                        }
                    }
                    return joinPoint.proceed(args);
                }
                case SELECT -> {
                    Object result = joinPoint.proceed(args);
                    // 处理结果解密
                    if (result != null) {
                        result = encryptionService.decryptObject(result);
                    }
                    return result;
                }
                default -> {
                    return joinPoint.proceed(args);
                }
            }
        }
        return joinPoint.proceed(args);
    }
}